if (!G_LIKELY (display_x11->trusted_client))
return;
- escaped_id = escape_for_xmessage (display_x11->startup_notification_id);
+ gdk_notify_startup_complete_with_id (display_x11->startup_notification_id);
+}
+
+/**
+ * gdk_notify_startup_complete_with_id:
+ * @startup_id: a startup-notification identifier, for which notification
+ * process should be completed
+ *
+ * Indicates to the GUI environment that the application has finished
+ * loading, using a given identifier.
+ *
+ * GTK+ will call this function automatically for #GtkWindow with custom
+ * startup-notification identifier unless
+ * gtk_window_set_auto_startup_notification() is called to disable
+ * that feature.
+ *
+ * Since: 2.12
+ **/
+void
+gdk_notify_startup_complete_with_id (const gchar* startup_id)
+{
+ GdkDisplay *display;
+ gchar *escaped_id;
+ gchar *message;
+
+ display = gdk_display_get_default ();
+ if (!display)
+ return;
+
+ escaped_id = escape_for_xmessage (startup_id);
message = g_strdup_printf ("remove: ID=%s", escaped_id);
g_free (escaped_id);
g_free (message);
}
-
/**
* gdk_display_supports_selection_notification:
* @display: a #GdkDisplay
}
+/**
+ * gdk_x11_display_get_startup_notification_id:
+ * @display: a #GdkDisplay
+ *
+ * Returns: the startup notification ID for
+ * @display.
+ *
+ * Since: 2.12
+ */
+G_CONST_RETURN gchar *
+gdk_x11_display_get_startup_notification_id (GdkDisplay *display)
+{
+ return GDK_DISPLAY_X11 (display)->startup_notification_id;
+}
+
#define __GDK_DISPLAY_X11_C__
#include "gdkaliasdef.c"
}
}
+/**
+ * gdk_window_set_startup_id:
+ * @window: a toplevel #GdkWindow
+ * @startup_id: a string with startup-notification identifier
+ *
+ * When using GTK+, typically you should use gtk_window_set_startup_id()
+ * instead of this low-level function.
+ *
+ * Since: 2.12
+ *
+ **/
+void
+gdk_window_set_startup_id (GdkWindow *window,
+ const gchar *startup_id)
+{
+ GdkDisplay *display;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ display = gdk_drawable_get_display (window);
+
+ if (!GDK_WINDOW_DESTROYED (window))
+ {
+ if (startup_id)
+ XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"),
+ gdk_x11_get_xatom_by_name_for_display (display, "UTF8_STRING"), 8,
+ PropModeReplace, startup_id, strlen (startup_id));
+ else
+ XDeleteProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_STARTUP_ID"));
+ }
+}
+
/**
* gdk_window_set_transient_for:
* @window: a toplevel #GdkWindow
#include <config.h>
#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
#include <limits.h>
#include "gdk/gdk.h"
#include "gdk/gdkkeysyms.h"
PROP_IS_ACTIVE,
PROP_HAS_TOPLEVEL_FOCUS,
+ /* Writeonly properties */
+ PROP_STARTUP_ID,
+
LAST_ARG
};
guint reset_type_hint : 1;
GdkWindowTypeHint type_hint;
+
+ gchar *startup_id;
};
static void gtk_window_dispose (GObject *object);
GTK_TYPE_DIRECTION_TYPE, direction);
}
+static guint32
+extract_time_from_startup_id (const gchar* startup_id)
+{
+ gchar *timestr = g_strrstr (startup_id, "_TIME");
+ guint32 retval = GDK_CURRENT_TIME;
+
+ if (timestr)
+ {
+ gchar *end;
+ guint32 timestamp;
+
+ /* Skip past the "_TIME" part */
+ timestr += 5;
+
+ timestamp = strtoul (timestr, &end, 0);
+ if (end != timestr && errno == 0)
+ retval = timestamp;
+ }
+
+ return retval;
+}
+
+static gboolean
+startup_id_is_fake (const gchar* startup_id)
+{
+ return strncmp (startup_id, "_TIME", 5) == 0;
+}
static void
gtk_window_class_init (GtkWindowClass *klass)
P_("Unique identifier for the window to be used when restoring a session"),
NULL,
GTK_PARAM_READWRITE));
+
+ /**
+ * GtkWindow:startup-id:
+ *
+ * The :startup-id is a write-only property for setting window's
+ * startup notification identifier. See gtk_window_set_startup_id()
+ * for more details.
+ *
+ * Since: 2.12
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_ROLE,
+ g_param_spec_string ("startup-id",
+ P_("Startup ID"),
+ P_("Unique startup identifier for the window used by startup-notification"),
+ NULL,
+ GTK_PARAM_WRITABLE));
g_object_class_install_property (gobject_class,
PROP_ALLOW_SHRINK,
priv->focus_on_map = TRUE;
priv->deletable = TRUE;
priv->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
+ priv->startup_id = NULL;
colormap = _gtk_widget_peek_colormap ();
if (colormap)
case PROP_ROLE:
gtk_window_set_role (window, g_value_get_string (value));
break;
+ case PROP_STARTUP_ID:
+ gtk_window_set_startup_id (window, g_value_get_string (value));
+ break;
case PROP_ALLOW_SHRINK:
window->allow_shrink = g_value_get_boolean (value);
gtk_widget_queue_resize (GTK_WIDGET (window));
g_object_notify (G_OBJECT (window), "role");
}
+/**
+ * gtk_window_set_startup_id:
+ * @window: a #GtkWindow
+ * @startup_id: a string with startup-notification identifier
+ *
+ * Startup notification identifiers are used by desktop environment to
+ * track application startup, to provide user feedback and other
+ * features. This function changes the corresponding property on the
+ * underlying GdkWindow. Normally, startup identifier is managed
+ * automatically and you should only use this function in special cases
+ * like transferring focus from other processes. You should use this
+ * function before calling gtk_window_present() or any equivalent
+ * function generating a window map event.
+ *
+ * This function is only useful on X11, not with other GTK+ targets.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_window_set_startup_id (GtkWindow *window,
+ const gchar *startup_id)
+{
+ GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (window);
+
+ g_return_if_fail (GTK_IS_WINDOW (window));
+
+ g_free (priv->startup_id);
+ priv->startup_id = g_strdup (startup_id);
+
+ if (GTK_WIDGET_REALIZED (window))
+ {
+ /* Here we differentiate real and "fake" startup notification IDs,
+ * constructed on purpose just to pass interaction timestamp
+ */
+ if (startup_id_is_fake (priv->startup_id))
+ {
+ guint32 timestamp = extract_time_from_startup_id (priv->startup_id);
+
+ gtk_window_present_with_time (window, timestamp);
+ }
+ else
+ {
+ gdk_window_set_startup_id (GTK_WIDGET (window)->window,
+ priv->startup_id);
+
+ /* If window is mapped, terminate the startup-notification too */
+ if (GTK_WIDGET_MAPPED (window) && !disable_startup_notification)
+ gdk_notify_startup_complete_with_id (priv->startup_id);
+ }
+ }
+
+ g_object_notify (G_OBJECT (window), "startup-id");
+}
+
/**
* gtk_window_get_role:
* @window: a #GtkWindow
if (window->frame)
gdk_window_show (window->frame);
- if (!disable_startup_notification &&
- !sent_startup_notification)
+ if (!disable_startup_notification)
{
- sent_startup_notification = TRUE;
- gdk_notify_startup_complete ();
+ /* Do we have a custom startup-notification id? */
+ if (priv->startup_id != NULL)
+ {
+ /* Make sure we have a "real" id */
+ if (!startup_id_is_fake (priv->startup_id))
+ gdk_notify_startup_complete_with_id (priv->startup_id);
+
+ priv->startup_id = NULL;
+ }
+ else if (!sent_startup_notification)
+ {
+ sent_startup_notification = TRUE;
+ gdk_notify_startup_complete ();
+ }
}
}
GtkWindowPrivate *priv;
window = GTK_WINDOW (widget);
-
priv = GTK_WINDOW_GET_PRIVATE (window);
/* ensure widget tree is properly size allocated */
gdk_window_set_modal_hint (widget->window, TRUE);
else
gdk_window_set_modal_hint (widget->window, FALSE);
+
+ if (priv->startup_id)
+ {
+#ifdef GDK_WINDOWING_X11
+ guint32 timestamp = extract_time_from_startup_id (priv->startup_id);
+ if (timestamp != GDK_CURRENT_TIME)
+ gdk_x11_window_set_user_time (widget->window, timestamp);
+#endif
+ if (!startup_id_is_fake (priv->startup_id))
+ gdk_window_set_startup_id (widget->window, priv->startup_id);
+ }
/* Icons */
gtk_window_realize_icon (window);